Python面向对象

373次阅读
没有评论

共计 5833 个字符,预计需要花费 15 分钟才能阅读完成。

Python 中,一切皆对象。每个对象由:标识(identity)、类型(type)、值(value)组成。

id(obj)返回对象 obj 的标识;type(obj)返回对象 obj 的类型;print(obj)直接打印出对象 obj 的值。

同一运算符:is用来比较 id,==用来比较值(本质是调用__eq__())。is 运算符比 == 效率高,在变量和 None 进行比较时,应使用 is。

特殊成员

在 Python 类中存在一些特殊方法(一般称之为魔术方法),这些方法都是 __方法__ 格式,这种方法(内置方法)在内部均有特殊含义。

__init__初始化方法

专门用来定义一个类具有哪些属性的方法。

__del__方法

对象被从内存中销毁前,会被自动调用。

__new__构造方法

很少用,但比较重要。使用类名 () 创建对象时,Python 解释器首先调用__new__方法为对象分配空间。

__new__是由 object 基类提供的内置静态方法,主要作用有 2 个:

  • 在内存中为对象分配空间
  • 返回对象的引用
class Foo(object):
    def __init__(self, name):
        print("第二步:初始化对象,在空对象中创建数据")
        self.name = name

    def __new__(cls, *args, **kwargs):
        print("第一步:先创建空对象并返回")
        return object.__new__(cls)

obj = Foo("李小龙")

__call__方法

class Foo(object):
    def __call__(self, *args, **kwargs):
        print("执行 call 方法")

obj = Foo()
obj() # 对象 +()执行 call 方法

__str__方法

当使用 print 输出对象的时候,如果定义了__str__方法,那么就会打印从这个方法中 return 的数据。该方法需要返回一个字符串。

class Foo(object):
    def __init__(self, name):
        self.name = name

    def __str__(self):
        return "我是{}".format(self.name)

obj = Foo('李小龙')
print(obj) # 结果为:我是李小龙

__repr__这个特殊方法会在对当前对象使用 repr()函数时调用,它的作用是指定对象在 ’ 交互模式 ’ 中直接输出的效果。

__dict__方法

class Foo(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age

obj = Foo('李小龙', 18)
print(obj.__dict__)

用类名调用__dict__,会输出该类中所有类属性组成的字典;而使用类的实例对象调用__dict__,会输出所有实例属性组成的字典。

__getitem__方法、__setitem__方法、__delitem__方法

class Foo(object):
    def __getitem__(self, item):
        print(item)

    def __setitem__(self, key, value):
        print(key, value)

    def __delitem__(self, key):
        print('删除')

obj = Foo()
obj["x1"] # 自动触发类中__getitem__
obj['x2'] = 123 # 自动触发类中__setitem__
del obj['x3'] # 自动触发类中__delitem__

__enter__和__exit__方法

class Foo(object):
    def __enter__(self):
        print("进来了")
        return 666

    def __exit__(self, exc_type, exc_val, exc_tb):
        print("出去了")

obj = Foo()
# with 对象 as f:在内部会执行__enter__方法,这时 f 是 666
# 当 with 缩进中的代码执行完毕,会自动执行__exit__方法
with obj as f:
    print(123)
    print(f)

输出结果如下:

进来了
123
666
出去了

__add__等

对象 + 值,内部会去执行 对象.__add__方法,并将 + 后面的值当做参数传递过去。

class Foo(object):
    def __init__(self, age):
        self.age = age

    def __add__(self, other):
        return self.age + other.age

obj1 = Foo(18)
obj2 = Foo(20)
obj = obj1 + obj2
print(obj) # 结果为:38

__iter__方法

迭代器

迭代器类型的定义:

  1. 类中定义 iternext 这两个方法
  2. iter 方法需要返回对象本身,即:self
  3. next 方法返回下一个数据,如果没有数据了,则需要抛出一个 StopIteration 的异常
class IT(object): # 创建迭代器类型
    def __init__(self):
        self.counter = 0

    def __iter__(self):
        return self

    def __next__(self):
        self.counter += 1
        if self.counter == 3:
            raise StopIteration()
        return self.counter

# 根据类实例化一个迭代器对象:obj1 = IT()
v1 = next(obj1) # obj1.__next__()
print(v1) # 结果为:1

v2 = next(obj1)
print(v2) # 结果为:2

# v3 = next(obj1) # 抛出异常
# print(v3)

obj2 = IT()
for item in obj2:
    print(item)

for 循环内部在循环时,先执行__iter__方法,获取一个迭代器对象,然后不断执行的__next__取值(有异常 StopIteration 则终止循环)。

生成器

# 创建生成器函数
def func():
    yield 1
    yield 2

# 创建生成器对象(内部是根据生成器类 generator 创建的对象),生成器类的内部也声明了__iter__、__next__方法
obj = func()

v1 = next(obj)
print(v1) # 结果为:1

v2 = next(obj)
print(v2) # 结果为:2

## v3 = next(obj) # StopIteration
## print(v3)

for item in obj:
    print(item)

如果按照迭代器的规定来看,其实生成器类也是一种特殊的迭代器类(生成器也是一种特殊的迭代器)。

可迭代对象

如果一个类中有__iter__方法且返回一个迭代器对象,则称这个类创建的对象为可迭代对象。

class IT(object): # 创建迭代器类型
    def __init__(self):
        self.counter = 0

    def __iter__(self):
        return self

    def __next__(self):
        self.counter += 1
        if self.counter == 3:
            raise StopIteration()
        return self.counter

class Foo(object):
      def __iter__(self):
          return IT()

obj = Foo() # obj 是可迭代对象
for item in obj:
    print(item)

继承

mro 和 c3 算法

如果类中存在继承关系,可以通过 mro() 获取当前类的继承关系。

class A(object):
    pass

class B(object):
    pass

class C(A, B):
    pass

print(C.mro())
print(C.__mro__)

输出结果如下:

[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]
(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)

如果用正经的 C3 算法规则去分析一个类继承关系有点繁琐,尤其是遇到一个复杂的类要分析很久。总结:从左到右,深度优先,大小钻石,留住顶端,基于这句话可以更快的找到继承关系。

类方法

类属性是针对类对象定义的属性,类方法是针对类对象定义的方法。语法如下:

class Tool():
    count = 0  # 类属性
    @classmethod  # 类方法,用修饰器 @classmethod 来标识
    def show_count(cls):
        print(f'工具对象的数量为 {cls.count}')

    def __init__(self, name):
        self.name = name
        Tool.count += 1

## 创建工具对象
tool = Tool('斧头')
tool2 = Tool('锯子')
# 调用类方法
Tool.show_count()

静态方法

如果类中封装的一个方法:

  • 既不需要访问实例属性或者调用实例方法
  • 也不需要访问类属性或者调用类方法

这个时候,就可以把这个方法封装成一个静态方法。静态方法既不需要传递类对象也不需要传递实例对象,有利于减少不必要的内存占用和性能消耗。

静态方法用修饰器 @staticmethod 来标识:

class Tool():
    @staticmethod
    def show():
        print('工具对象')

    def __init__(self, name):
        self.name = name

# 创建工具对象
tool = Tool('斧头')
# 调用类方法
Tool.show()

单例

让类创建的对象,在系统中只有唯一的一个实例,即单例。实现步骤为:

  1. 定义一个类属性,初始值为 None,用于记录单例对象的引用
  2. 重写__new__方法
  3. 如果类属性 is None,调用父类方法分配空间,并在类属性中记录结果
  4. 返回类属性中记录的对象引用
class Tool():
    instance = None
    def __new__(cls, *args, **kwargs):
        if cls.instance is None:
            cls.instance = super().__new__(cls)
        return cls.instance

tool = Tool()
tool2 = Tool()
print(tool)
print(tool2)

只执行一次初始化

每次使用类名 () 创建对象时,Python 解释器会自动调用两个方法:__new__、__init__。要让初始化动作只被执行一次,实现步骤为:

  1. 定义一个类属性 init_flag,标记是否执行过初始化动作,初始值为 False
  2. 在__init__方法中,判断 init_flag,如果为 False 就执行初始化动作
  3. 然后将 init_flag 设置为 True
class Tool():
    instance = None
    init_flag = False

    def __new__(cls, *args, **kwargs):
        if cls.instance is None:
            cls.instance = super().__new__(cls)
        return cls.instance

    def __init__(self):
        if Tool.init_flag:
            return
        print('初始化')
        Tool.init_flag = True

tool = Tool()
tool2 = Tool()
print(tool)
print(tool2)

装饰器

Python 内置的 @property 装饰器负责把一个方法变成属性调用。

class Square:
    def __init__(self, w, h):
        self.__height = h
        self.__width = w
  
    def set_side(self, new_side):
        self.__height = new_side
        self.__width = new_side

    @property
    def height(self):
        return self.__height

    @height.setter
    def height(self, new_value):
        if new_value >= 0:
            self.__height = new_value
        else:
            raise Exception("Value must be larger than 0")

s = Square(2, 2)
print(s.height)  # 2
s.height = 5
print(s.height)  # 5

把一个 getter 方法变成属性,只需要加上 @property 就可以了。此时,@property 本身又创建了另一个装饰器 @height.setter,负责把一个 setter 方法变成属性赋值。

只定义 getter 方法,不定义 setter 方法就是一个只读属性。

类属性方式

class A:
    def __init__(self):
        self.__age = 0

    def get_age(self):
        return self.__age

    def set_age(self, age):
        if age < 0 or age > 120:
            raise ValueError("Invalid age")
        self.__age = age

    # 类属性方式的 property 属性
    age = property(get_age, set_age)

a = A()
print(a.age)  # 0
a.age = 25
print(a.age)  # 25

多态

多态是指同一个方法调用由于对象不同可能会产生不同的行为。关于多态要注意以下 2 点:

  • 多态是方法的多态,属性没有多态
  • 多态的存在有 2 个必要条件:继承、方法重写

抽象类

默认情况下,Python 不提供抽象类,但 abc 模块为定义抽象基类提供了基础。抽象类的价值更多作用是在于设计,是设计者设计好后,让子类继承并实现抽象类的抽象方法。

当需要抽象基类时,让类继承 ABC(abc 模块的 ABC 类),使用 @abstractmethod 声明抽象方法,那么这个类就是抽象类。

from abc import ABC, abstractmethod

class Animal(ABC):
    def __init__(self, name):
        self.name = name

    @abstractmethod
    def speak(self):
        pass

# 抽象类不能实例化,只能被继承,不能创建对象
# a = Animal("dog")

class Dog(Animal):
    def speak(self):
        print(f"{self.name} 汪汪叫")

dog = Dog("狗")
dog.speak()

正文完
 0
阿伯手记
版权声明:本站原创文章,由 阿伯手记 于2023-08-02发表,共计5833字。
转载说明:本站原创内容,除特殊说明外,均基于 CC BY-NC-SA 4.0 协议发布,转载须注明出处与链接。
评论(没有评论)
验证码

阿伯手记

阿伯手记
阿伯手记
喜欢编程,头发渐稀;成长路上,宝藏满地
文章数
767
评论数
207
阅读量
682528
今日一言
-「
热门文章
职场救急!AI请假话术生成器:1秒定制高通过率理由

职场救急!AI请假话术生成器:1秒定制高通过率理由

超级借口 不好开口?借口交给我!智能生成工作请假、上学请假、饭局爽约、约会拒绝、邀约推辞、万能借口等各种借口理...
夸克网盘快传助手提高非VIP下载速度

夸克网盘快传助手提高非VIP下载速度

夸克网盘限速这个大家都知道,不开会员差不多限速在几百 K。那有没有办法在合法合规途径加速下载夸克网盘呢?这里推...
TVAPP:开源电视盒子资源库,一键打造家庭影院

TVAPP:开源电视盒子资源库,一键打造家庭影院

导语 TVAPP 是一个专为 Android TV 电视盒子用户打造的开源影音资源库,集成了影视、直播、游戏等...
巴别英语:用美剧和TED演讲轻松提升英语听力与口语

巴别英语:用美剧和TED演讲轻松提升英语听力与口语

还在为枯燥的英语学习而烦恼吗?巴别英语通过创新的美剧学习模式,让英语学习变得生动有趣。平台提供海量美剧和 TE...
Chinese Name Generator 在线中文姓名生成器

Chinese Name Generator 在线中文姓名生成器

Chinese Name Generator 是一款在线中文姓名生成器,可在几秒内生成符合个人需求的中文名字。...
2025年12月 每日精选

2025年12月 每日精选

关于每日精选栏目 发现一些不错的资源,点击 这里 快速投稿。 12 月 26 日 .ax 顶级域 目前全球唯一...
123云盘限时福利:登录即送1个月VIP尊享权益!

123云盘限时福利:登录即送1个月VIP尊享权益!

🎁  零成本体验 20T 超大空间与会员加速通道 🎉 活动亮点 登录即送:无需任何复杂操作,登录账号直接领取 ...
最新评论
阿伯手记 阿伯手记 发了:https://aboss.top/moments/1064
吴蛋蛋 吴蛋蛋 快发小年快乐
吴蛋蛋 吴蛋蛋 Ask4Me,这个之前看server酱接入了
15220202929 15220202929 怎么用
八对 八对 麻烦大佬更新下【堆新】的友链站名:八对星星描述:极目星视穹苍无界•足履行者大地有疆链接:https://8dui.com图标:https://cf.8dui.com/logo.webp横标:https://cf.8dui.com/logo-w.webp订阅:https://8dui.com/rss.xml
三毛笔记 三毛笔记 已添加
DUINEW DUINEW 已添加贵站,期待贵站友链~博客名称:堆新博客地址:https://duinew.com/博客描述:堆新堆新,引力向新!——堆新(DUINEW)博客头像:https://d.duinew.com/logo.webp横版头像:https://d.duinew.com/logo-w.webp博客订阅:https://duinew.com/rss.xml
hedp hedp 没看懂
bingo bingo 直接生成就可以啦,也可以添加一些选项
热评文章
夸克网盘快传助手提高非VIP下载速度

夸克网盘快传助手提高非VIP下载速度

夸克网盘限速这个大家都知道,不开会员差不多限速在几百 K。那有没有办法在合法合规途径加速下载夸克网盘呢?这里推...
Short-Link 免费开源短网址程序,基于Fastify、Vercel和Supabase构建

Short-Link 免费开源短网址程序,基于Fastify、Vercel和Supabase构建

Short-Link 是一款基于 Fastify、Vercel 和 Supabase 构建的 URL 缩短服务...
清华大学官方免费DeepSeek教程

清华大学官方免费DeepSeek教程

AI 领域近期最引人注目的焦点当属 DeepSeek,这款由中国创新企业深度求索研发的人工智能工具,正以开放源...
Chinese Name Generator 在线中文姓名生成器

Chinese Name Generator 在线中文姓名生成器

Chinese Name Generator 是一款在线中文姓名生成器,可在几秒内生成符合个人需求的中文名字。...
2026年2月 每日精选

2026年2月 每日精选

关于每日精选栏目 发现一些不错的资源,点击 这里 快速投稿。 2 月 17 日 国家全民健身信息服务平台 过年...
DrawLink:一键生成链接视觉卡片,提升分享点击率

DrawLink:一键生成链接视觉卡片,提升分享点击率

小贴士 :此站或已变迁,但探索不止步。我们已为您备好「类似网站」精选合集,相信其中的发现同样能为您带来惊喜。
WebRTC Screen Mirror:基于浏览器免费开源投屏神器,可实现低延迟、跨平台屏幕共享

WebRTC Screen Mirror:基于浏览器免费开源投屏神器,可实现低延迟、跨平台屏幕共享

WebRTC Screen Mirror 是一款基于 WebRTC 技术的在线屏幕共享工具,它利用浏览器内置的...